package valuecomusa.fijibus.eticket;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.LocationManager;
import android.media.MediaPlayer;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.nfc.tech.MifareUltralight;
import android.os.Build;
import android.os.Environment;
import android.os.Parcelable;
import android.util.Log;
import android.widget.Toast;
import org.kobjects.base64.Base64;
import valuecomusa.nfc.record.TextRecord;
import valuecomusa.nfc.record.UriRecord;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class Utilities
{

    static final String TAG = "Utilities";

    public static Date StringToDate(String value)
    {
        Date convertedDate;
        try
        {
            String format = "yyyy-MM-dd'T'HH:mm:ss";
            if (value.length() > 23)
                format = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
            else if (value.length() > 19)
                format = "yyyy-MM-dd'T'HH:mm:ss.SSS";
            SimpleDateFormat dateFormat = new SimpleDateFormat(format);
            convertedDate = dateFormat.parse(value);
        }
        catch (ParseException e)
        {
            e.printStackTrace();
            convertedDate = null;
        }
        return convertedDate;

    }

    public static String DateToString(Date date)
    {
        try
        {
            SimpleDateFormat fdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
            return fdf.format(date);
        }
        catch (Exception e)
        {
            Log.e(TAG, e.getMessage());
        }
        return "";
    }

    public static String DateToString(Date date, String format)
    {
        try
        {
            SimpleDateFormat fdf = new SimpleDateFormat(format);
            return fdf.format(date);
        }
        catch (Exception e)
        {
            Log.e(TAG, e.getMessage());
        }
        return "";
    }

    public static String getHex(byte[] bytes)
    {
        StringBuilder sb = new StringBuilder();
        /*
         * for (int i = bytes.length - 1; i >= 0; --i) { int b = bytes[i] &
		 * 0xff; if (b < 0x10) sb.append('0');
		 * sb.append(Integer.toHexString(b)); if (i > 0) { sb.append(" "); } }
		 */
        for (int i = 0; i < bytes.length; i++)
        {
            int b = bytes[i] & 0xff;
            if (b < 0x10)
                sb.append('0');
            sb.append(Integer.toHexString(b));
        }
        return sb.toString();
    }

    public static long getDec(byte[] bytes)
    {
        long result = 0;
        long factor = 1;
        for (int i = 0; i < bytes.length; ++i)
        {
            long value = bytes[i] & 0xffl;
            result += value * factor;
            factor *= 256l;
        }
        return result;
    }

    public static String dumpTagData(Parcelable p)
    {
        StringBuilder sb = new StringBuilder();
        Tag tag = (Tag) p;
        byte[] id = tag.getId();
        sb.append("Tag ID (hex): ").append(getHex(id)).append("\n");
        sb.append("Tag ID (dec): ").append(getDec(id)).append("\n");

        String prefix = "android.nfc.tech.";
        sb.append("Technologies: ");
        for (String tech : tag.getTechList())
        {
            sb.append(tech.substring(prefix.length()));
            sb.append(", ");
        }
        sb.delete(sb.length() - 2, sb.length());
        for (String tech : tag.getTechList())
        {
            if (tech.equals(MifareClassic.class.getName()))
            {
                sb.append('\n');
                MifareClassic mifareTag = MifareClassic.get(tag);
                String type = "Unknown";
                switch (mifareTag.getType())
                {
                    case MifareClassic.TYPE_CLASSIC:
                        type = "Classic";
                        break;
                    case MifareClassic.TYPE_PLUS:
                        type = "Plus";
                        break;
                    case MifareClassic.TYPE_PRO:
                        type = "Pro";
                        break;
                }
                sb.append("Mifare Classic type: ");
                sb.append(type);
                sb.append('\n');

                sb.append("Mifare size: ");
                sb.append(mifareTag.getSize() + " bytes");
                sb.append('\n');

                sb.append("Mifare sectors: ");
                sb.append(mifareTag.getSectorCount());
                sb.append('\n');

                sb.append("Mifare blocks: ");
                sb.append(mifareTag.getBlockCount());
            }

            if (tech.equals(MifareUltralight.class.getName()))
            {
                sb.append('\n');
                MifareUltralight mifareUlTag = MifareUltralight.get(tag);
                String type = "Unknown";
                switch (mifareUlTag.getType())
                {
                    case MifareUltralight.TYPE_ULTRALIGHT:
                        type = "Ultralight";
                        break;
                    case MifareUltralight.TYPE_ULTRALIGHT_C:
                        type = "Ultralight C";
                        break;
                }
                sb.append("Mifare Ultralight type: ");
                sb.append(type);
            }
        }

        return sb.toString();
    }

    public static String[] readNFCTagContentAndSerial(Context cxt, Intent intent)
    {
        if (intent == null)
            return null;

        String action = intent.getAction();

        if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)
                || action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED))
        {
            // When a tag is discovered we send it to the service to be save. We
            // include a PendingIntent for the service to call back onto. This
            // will cause this activity to be restarted with onNewIntent(). At
            // that time we read it from the database and view it.
            Parcelable[] rawMsgs = intent
                    .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            NdefMessage[] msgs;
            String content = "";
            String serial = "";

            if (rawMsgs != null)
            {
                msgs = new NdefMessage[rawMsgs.length];
                for (int i = 0; i < rawMsgs.length; i++)
                {
                    msgs[i] = (NdefMessage) rawMsgs[i];

                    for (NdefRecord record : msgs[i].getRecords())
                    {
                        if (UriRecord.isUri(record))
                        {
                            UriRecord.parse(record);
                        } else if (TextRecord.isText(record))
                        {
                            TextRecord tr = TextRecord.parse(record);
                            content += tr.getText();
                        }
                    }
                }

                WorkingSession.getInstance().ShowToast(cxt, "Read Tag successful", Toast.LENGTH_SHORT);;

                Tag taginfo = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                serial = getHex(taginfo.getId());
                //--
                String keyBytes = "01234567899876543210112233445566";
                String val;
                try
                {
                    val = Utilities.RijndaelECBDecrypt(content, keyBytes);
                    //Log.i(TAG, val);
                }
                catch(Exception ex)
                {
                    Log.e(TAG, ex.getMessage());
                    val = "";
                }

                return new String[]{serial, val};

            }
            else
            {
                // Unknown tag type
                byte[] empty = new byte[0];

                byte[] id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);
                Parcelable tag = intent
                        .getParcelableExtra(NfcAdapter.EXTRA_TAG);
                String info = dumpTagData(tag);
                Log.i(TAG, "Unknown TAG type. " + info);

                WorkingSession.getInstance().ShowToast(cxt, "Unknown Tag", Toast.LENGTH_SHORT);;

                /*byte[] payload = info.getBytes();
                NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,
                        empty, id, payload);
                NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
                msgs = new NdefMessage[]{msg};*/

                return null;
            }
        }
        else
        {
            Log.i(TAG, "Invalid action. " + intent);
            return null;
        }
    }

    public static String getDeviceInfo()
    {
        String serialNo = null;

        try
        {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class, String.class);
            serialNo = (String) (get.invoke(c, "ro.serialno", "unknown"));
        }
        catch (Exception ignored)
        {
        }
        /*String androidId = Settings.Secure.ANDROID_ID;

        StringBuffer buf = new StringBuffer();
        buf.append("ver:" + Build.VERSION.RELEASE);
        buf.append("." + Build.VERSION.INCREMENTAL);
        buf.append("-sdk:" + Build.VERSION.SDK_INT);
        buf.append("-fp:" + Build.FINGERPRINT);
        buf.append("-board:" + Build.BOARD);
        buf.append("-brand:" + Build.BRAND);
        buf.append("-device:" + Build.DEVICE);
        buf.append("-man:" + Build.MANUFACTURER);
        buf.append("-model:" + Build.MODEL);*/

        return String.format("%s-%s", serialNo, Build.MODEL);
    }

    //--Decrypt 32bit AES
    public static String RijndaelECBDecrypt(String text, String key) throws Exception
    {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
        byte[] keyBytes = new byte[32];
        byte[] b = key.getBytes("UTF-8");
        int len = b.length;
        if (len > keyBytes.length) len = keyBytes.length;
        System.arraycopy(b, 0, keyBytes, 0, len);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);

        byte[] results = cipher.doFinal(Base64.decode(text));
        return new String(results, "UTF-8");
    }

    //--Encrypt 32bit AES
    public static String RijndaelECBEncrypt(String text, String key)
            throws Exception
    {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
        byte[] keyBytes = new byte[32];
        byte[] b = key.getBytes("UTF-8");
        int len = b.length;
        if (len > keyBytes.length) len = keyBytes.length;
        System.arraycopy(b, 0, keyBytes, 0, len);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");

        cipher.init(Cipher.ENCRYPT_MODE, keySpec);

        byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
        return Base64.encode(results);
    }

    public static boolean isGPSEnable(Context cxt)
    {
        LocationManager locationManager = (LocationManager) cxt.getSystemService(cxt.LOCATION_SERVICE);
        // getting GPS status
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }

    public static MediaPlayer PlayMedia(Context cxt, String name)
    {
        return PlayMedia(cxt, name, null);
    }

	public static MediaPlayer PlayMedia(Context cxt, String name, MediaPlayer.OnCompletionListener onCompleted)
	{
		File mp3File = new File(Environment.getExternalStorageDirectory() + Declarations.ShortHaul_sdCard_Folder + name);
		MediaPlayer mediaPlayer = null;
		if(!mp3File.exists())
		{
			WorkingSession.getInstance().ShowToast(
					cxt,
					"File not found. " + mp3File.getAbsolutePath(),
					Toast.LENGTH_SHORT
			);
			return null;
		}
		else
		{
			try
			{
				FileDescriptor fd = null;
				FileInputStream fileStream = new FileInputStream(mp3File);
				fd = fileStream.getFD();
				//--
				mediaPlayer = new MediaPlayer();
				if(onCompleted != null)
					mediaPlayer.setOnCompletionListener(onCompleted);
				mediaPlayer.setDataSource(fd);
				mediaPlayer.prepare();
				mediaPlayer.start();
			}
			catch (Exception ex)
			{
				Log.e(TAG, String.format("Play file %s error. %s", name, ex.getMessage()));
				WorkingSession.getInstance().ShowToast(
						cxt,
						"Play file error. " + mp3File.getAbsolutePath() + "\n"
								+ ex.getMessage(),
						Toast.LENGTH_SHORT
				);
				return null;
			}
		}

		return mediaPlayer;
	}

    public static String StringAlignCenter(int width, String data)
    {
        if(data == null || data.length() == 0)
            return "";
        if(data.length() >= width)
            return data;
        //--
        int padCount = (width - data.length()) / 2;
        char[] x = data.toCharArray();

        char[] result = new char[width];
        Arrays.fill(result, ' ');
        System.arraycopy(x, 0, result, padCount, x.length);

        return String.valueOf(result);
    }

    public static String StringAlignLeftRight(int width, String leftData, String rightData)
    {
        if(leftData == null || leftData.length() == 0)
            leftData = " ";
        if(rightData == null || rightData.length() == 0)
            rightData = " ";

        if(leftData.length() + rightData.length() >= width)
        {
            if(leftData.length() >= width/2)
            {
                leftData = leftData.substring(0, leftData.length()-10);
                leftData += "...";
            }
            if(rightData.length() >= width/2)
            {
                rightData = rightData.substring(0, rightData.length()-10);
                rightData += "...";
            }
        }
        //--
        int padCount = width - (leftData.length() + rightData.length());
        char[] x = leftData.toCharArray();
        char[] y = rightData.toCharArray();

        char[] result = new char[width];
        Arrays.fill(result, ' ');
        System.arraycopy(x, 0, result, 0, x.length);
        System.arraycopy(y, 0, result, leftData.length() + padCount, y.length);

        return String.valueOf(result);
    }

    public static boolean SaveResourceToSdCard(Context cxt, int resId, String sdCardFileName)
    {
        if(sdCardFileName == null || sdCardFileName.length() == 0)
            return false;

        File fileLocation = new File(Environment.getExternalStorageDirectory() + Declarations.ShortHaul_sdCard_Folder);
        if(!fileLocation.exists())
            fileLocation.mkdir();
        //--
        String filePath = Environment.getExternalStorageDirectory()
                + Declarations.ShortHaul_sdCard_Folder
                + sdCardFileName;

        Bitmap bm = BitmapFactory.decodeResource(cxt.getResources(), resId);
        if(bm == null)
        {
            Log.d(TAG, String.format("[SaveResourceToSdCard] Resource %d not found.", resId));
            return  false;
        }

        try
        {
            File file = new File(filePath);
            FileOutputStream outStream = new FileOutputStream(file);
            bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
            outStream.flush();
            outStream.close();
        }
        catch (Exception ex)
        {
            Log.e(TAG, "EXCEPTION: " + ex.getMessage());
            return false;
        }

        return true;
    }

    public static int getResId(String variableName, Context context, Class<?> c) {

        try
        {
            Field idField = c.getDeclaredField(variableName);
            return idField.getInt(idField);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            Log.e(TAG, "EXCEPTION: " + e.getMessage());
            return -1;
        }
    }
	public static String SaveBitmapToSdCard(Context cxt, Bitmap bitmap, String jpgFileName)
    {
        if(bitmap == null)
            return null;
        if(jpgFileName == null || jpgFileName.length() == 0)
            return null;

        File fileLocation = new File(Environment.getExternalStorageDirectory() + Declarations.ShortHaul_sdCard_Folder);
        if(!fileLocation.exists())
            fileLocation.mkdir();
        //--
        String filePath = fileLocation.getPath() + "/" + jpgFileName;

        try
        {
            File file = new File(filePath);
            FileOutputStream outStream = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
            outStream.flush();
            outStream.close();
        }
        catch (Exception ex)
        {
            Log.e(TAG, "EXCEPTION: " + ex.getMessage());
            return null;
        }

        return filePath;
    }

    public static boolean FileExistOnSdCard(String fileName)
    {
        File file = new File(Environment.getExternalStorageDirectory() +
                Declarations.ShortHaul_sdCard_Folder + fileName
        );
        return file.exists();
    }

	public static double DateDifferenceSecond(Date now, Date then)
	{
		return (double)(now.getTime() - then.getTime())/1000F;
	}
}
